package admin

import (
	"go.uber.org/zap"
	"sync"
	"time"
	"wzgames/internal/admin/adc"
	"wzgames/internal/admin/adsv/wscmd"
	"wzgames/internal/codec/sfs"
	"wzgames/internal/constant"
	"wzgames/pkg/actor/actor"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/common/timingwheel"
	"wzgames/pkg/logger"
	"wzgames/pkg/server/ws"
)

var (
	adminGuard *AdminGuard
	once       sync.Once
)

type AdminGuard struct {
	actorservice.ServiceMeta
	ws *ws.WebSocket

	timerWheel *timingwheel.TimingWheel
	t1         time.Duration
}

func Actor() actorservice.IService {
	if adminGuard == nil {
		once.Do(func() {
			adminGuard = &AdminGuard{
				timerWheel: timingwheel.NewTimingWheel(time.Second, 60),
				t1:         time.Minute,
			}
			adminGuard.Name = "actor_admin_guard"
		})
	}
	return adminGuard
}

func (ag *AdminGuard) OnReceive(ctx actor.Context) {
	switch m := ctx.Message().(type) {
	case *ws.MsgEvent:
		ag.sysControlMessage(m)
	default:
	}
}

func (ag *AdminGuard) OnStart(as *actorservice.ActorService) {
	if ag.ws != nil {
		ag.ws.SetReceiver(adc.NewWsReceiver(ag.GetPID()))
	}
	ag.timerWheel.Start()
	_ = adc.Init()
	adc.GetReceiver().SetMsgHandler(wscmd.Cmd().DoMessage)
	wscmd.InitCmd()
	ag.checkPlayerActive(nil)
}

func (ag *AdminGuard) Attach(a interface{}) {
	ag.SuperV = a
	v, ok := a.(*ws.WebSocket)
	if !ok {
		panic("invalid attach type")
	}
	ag.ws = v
}

func (ag *AdminGuard) OnDestroy() {
	ag.timerWheel.Stop()
	actorservice.Stop(ag.GetPID())
}

func (ag *AdminGuard) sysControlMessage(req *ws.MsgEvent) {
	defer logger.Recover()

	switch m := req.Message().(type) {
	case *sfs.TSfsObject:
		switch m.GetID() {
		case constant.ActionHandShake:
			adc.GetReceiver().HandleHandShake(req.Session(), m)
		case constant.ActionLogin:
			adc.GetReceiver().HandleLogin(req.Session(), m)
		default:
			logger.Warn("[Admin] illegal action id", zap.Uint16("ActionID", m.GetID()))
		}
	}
}

func (ag *AdminGuard) checkPlayerActive(args interface{}) {
	adc.GetReceiver().CheckAdminActive()
	ag.timerWheel.AfterFunc(ag.t1, ag.checkPlayerActive, nil)
}

func GetSession(sessId int64) ws.ISession {
	return adminGuard.ws.GetSession(sessId)
}
